/// 进程间通信 -- 匿名管道

// 1. 建立管道
// 2. 创建子进程
// 3. 关闭无用端
// 4. 进行通信

// 让父进程读 , 子进程写

#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void ChildWrite(int wfd)
{
    char buff[1024] = {0};
    int cnt = 0;
    int count = 12;
    while (count--)
    {
        // 格式化buff
        snprintf(buff, sizeof(buff), "I am child , I pid = %d , cnt = %d", getpid(), cnt++);
        ssize_t n = write(wfd, buff, strlen(buff));
        if (n > 0)
        {
            sleep(1); // 写成功了 , 休眠 2 s 继续写
        }
        else
        {
            continue;
        } // 写失败了 , 继续写
    }
}

void FatherRead(int rfd)
{
    char buff[1024] = {0};
    int count = 10;
    while (count--)
    {
        ssize_t n = read(rfd, buff, sizeof(buff) - 1);
        if (n < 0)
            continue;
        else if (n > 0)
        {
            // 读取成功 , 转化为字符串 , n 是实际读到的个数
            buff[n] = 0; // 放上 \0
            std::cout << "child say : " << buff << std::endl;
            std::cout << " read : n = " << n << std::endl;
            // sleep(5);
        }
        else
        {
            std::cout << " read : n = " << n << std::endl;
            std::cout << " read : n = " << n << std::endl;
            break;
        } // n == 0 , 读到文件末尾 , 结束
    }
}

int main()
{
    // 1. 建立管道 -- pipe 系统调用
    int fd[2] = {0}; // fd[0] - 读端  fd[1] - 写端
    int p = pipe(fd);
    if (p < 0)
        return 1;

    // 创建管道成功 -- 看看 fd[0] , fd[1] 是什么
    std::cout << "fd[0]" << fd[0] << std::endl;
    std::cout << "fd[1]" << fd[1] << std::endl;

    // 2 . 创建子进程 , 让父子进程先看看共享数据
    pid_t n = fork();
    if (n < 0)
        return 1;
    else if (n == 0)
    {
        // child
        //  3 . 关闭各自无用端口 ,  子进程写 , 关闭读端
        close(fd[0]);

        // 子进程写
        ChildWrite(fd[1]);

        close(fd[1]);
        exit(0);
    }

    // father
    // 3 . 关闭各自无用端口 ,  父进程读 , 关闭写端
    close(fd[1]);

    // 父进程读
    FatherRead(fd[0]);

    close(fd[0]);
    sleep(10);
    // 等待子进程 , 获取子进程退出信息
    int wstaus = 0;
    pid_t ret = waitpid(n, &wstaus, 0);
    if (ret > 1)
    {
        // 获取子进程退出信息
        std::cout << "子进程退出码 :" << ((wstaus >> 8) & 0xFF) << "子进程退出信号 :" << (wstaus&0x7F) << std::endl;
    }

    return 0;
}